package com.xbongbong.sys.model.impl;

import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.util.XssShieldUtil;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.enums.OrderTypeEnum;
import com.xbongbong.sys.domain.dao.FeeCompanyDao;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.FeeCompanyEntity;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.FeeCompanyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author kaka
 * @date  2018-9-3 15:43
 */
@Service("feeCompanyModel")
public class FeeCompanyModelImpl implements FeeCompanyModel {

    private static final Logger LOG = LoggerFactory.getLogger(FeeCompanyModelImpl.class);

    @Resource
    private FeeCompanyDao feeCompanyDao;
    /**
     * 本处是一处规范破例，此处逻辑耦合度较高，涉及一些底层方法调用
     */
    @Resource
    private FeeCompanyModel feeCompanyModel;
    @Resource
    private CompanyModel companyModel;

    @Override
    public FeeCompanyEntity getActiveFeeCompany(String corpid, String timeCondition, Integer timeStamp) {
        //默认是timeBetween
        if(StringUtil.isEmpty(timeCondition)) {
            timeCondition = TIME_BETWEEN;
        }

        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", 0);
        // 有效记录
        param.put("isActive", 1);
        // 除 TIME_BETWEEN 和 START_TIME_LT 以外，其他timeCondition值无效
        if(TIME_BETWEEN.equals(timeCondition)) {
            // timeBetween 用以筛选包含该时间戳节点的套餐
            param.put(TIME_BETWEEN, timeStamp);
        } else if(START_TIME_LT.equals(timeCondition)) {
            // timeBetween 用以筛选包含该时间戳节点的套餐
            param.put(START_TIME_LT, timeStamp);
        }

        // 只取一条记录
        param.put("start", 0);
        param.put("pageNum", 1);
        // end_time最大的记录
        param.put("orderByStr", "end_time DESC");
        List<FeeCompanyEntity> feeCompanies = feeCompanyDao.findEntitys(param);

        return feeCompanies.size() > 0 ? feeCompanies.get(0) : null;
    }

    @Override
    public FeeCompanyEntity getHistoryActiveFeeCompany(String corpid) {
        return getActiveFeeCompany(corpid,START_TIME_LT, DateUtil.getInt());
    }

    @Override
    public Integer insert(FeeCompanyEntity entity) throws XbbException {
        entity.setCorpName(XssShieldUtil.stripXss(entity.getCorpName()));
        Integer now = DateUtil.getInt();
        entity.setAddTime(now);
        entity.setUpdateTime(now);
        Integer index = feeCompanyDao.insert(entity);
        CompanyEntity company = companyModel.getByKey(entity.getCorpid());
        setFeeCompanyInfo4Company(company);
        return index;
    }

    @Override
    public Integer update(FeeCompanyEntity entity) throws XbbException {
        entity.setCorpName(XssShieldUtil.stripXss(entity.getCorpName()));
        entity.setUpdateTime(DateUtil.getInt());
        Integer index = feeCompanyDao.update(entity);
//        updateFeeCompanyInfoToCompany(entity.getCorpid());
        CompanyEntity company = companyModel.getByKey(entity.getCorpid());
        setFeeCompanyInfo4Company(company);
        return index;
    }

    @Override
    public Integer updateBatch(List<FeeCompanyEntity> list, String corpid) {
        if (CollectionsUtil.isEmpty(list)) {
            return 0;
        }
        return feeCompanyDao.updateBatch(list, corpid);
    }

    /**
     * 设置套餐渠道码
     * 套餐对应的公司存在渠道码的将此渠道码设置给此套餐
     * @param feeCompany
     * 创建时间 2018/9/30 2:46 PM
     * 修改时间 2018/9/30 2:46 PM
     * @author chy
     * @since v3.30
     * @version v3.30
     */
    private void setAuthChannelByCompany(FeeCompanyEntity feeCompany) {
        CompanyEntity company = companyModel.getByKey(feeCompany.getCorpid());

        //公司不存在或没有渠道码
        if(company == null || StringUtil.isEmpty(company.getAuthChannel())){
            return ;
        }

        //套餐上面已经有渠道码
        if(!StringUtil.isEmpty(feeCompany.getAuthChannel())){
            return ;
        }

        feeCompany.setAuthChannel(company.getAuthChannel());
    }

    private void updateFeeCompanyInfoToCompany(String corpid) throws XbbException {
        FeeCompanyEntity feeCompany = feeCompanyModel.getLastFeeCompanyIgnoreIsPay(corpid);

        CompanyEntity company = companyModel.getByKey(corpid);
        if(feeCompany == null || company == null) {
            return ;
        }

        Integer vipNum = feeCompanyModel.getBuyNum(corpid);
        company.setVipNum(vipNum);
        if(feeCompany != null) {
            company.setFeeStartTime(feeCompany.getStartTime());
            company.setFeeEndTime(feeCompany.getEndTime());
            company.setFeeName(feeCompany.getFeeName());
            company.setFeeUserNum(feeCompany.getUserNum());
//            company.setOrderType(feeCompany.getOrderType());
        }

        companyModel.update(company);
    }

    @Override
    public List<FeeCompanyEntity> findEntitys(Map<String, Object> param) {
        return feeCompanyDao.findEntitys(param);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return feeCompanyDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return null;
    }

    @Override
    public Integer getBuyNum(String corpid) {
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("isPay", 1);
        param.put("del", 0);
        return getEntitysCount(param);
    }

    @Override
    public Integer save(FeeCompanyEntity entity) throws XbbException {
        if (entity.getId() == null || Objects.equals(0, entity.getId())) {
            return insert(entity);
        }
        return update(entity);
    }

    @Override
    public void paidPackageUnavailable(String corpid) {
        feeCompanyDao.paidPackageUnavailable(corpid);
    }

    @Override
    public Integer deleteByKey(Integer key) {
        return feeCompanyDao.deleteByKey(key);
    }

    @Override
    public FeeCompanyEntity getByKey(Integer key) {
        return feeCompanyDao.getByKey(key);
    }

    @Override
    public FeeCompanyEntity getFirstFeeCompany(String corpid) {
        Map<String, Object> param = new HashMap<>(16);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("isPay", 1);
        param.put("start", 0);
        param.put("pageNum", 1);
        param.put("orderByStr", " add_time asc ");
        List<FeeCompanyEntity> firstFeeCompanyList = findEntitys(param);
        return firstFeeCompanyList.size() == 0 ? null : firstFeeCompanyList.get(0);
    }

    @Override
    public FeeCompanyEntity getFirstFeeCompanyIgnoreIsPay(String corpid) {
        Map<String, Object> param = new HashMap<>(16);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("start", 0);
        param.put("pageNum", 1);
        param.put("orderByStr", " add_time asc ");
        List<FeeCompanyEntity> firstFeeCompanyList = findEntitys(param);
        return firstFeeCompanyList.size() == 0 ? null : firstFeeCompanyList.get(0);
    }

    @Override
    public FeeCompanyEntity getLastFeeCompany(String corpid) {
        Map<String, Object> param = new HashMap<>(16);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("isPay", 1);
        param.put("start", 0);
        param.put("pageNum", 1);
        param.put("orderByStr", " add_time desc ");
        List<FeeCompanyEntity> firstFeeCompanyList = findEntitys(param);
        return firstFeeCompanyList.size() == 0 ? null : firstFeeCompanyList.get(0);
    }

    @Override
    public FeeCompanyEntity getLastFeeCompanyIgnoreIsPay(String corpid) {
        Map<String, Object> param = new HashMap<>(16);
        param.put("del", 0);
        param.put("corpid", corpid);
        param.put("start", 0);
        param.put("pageNum", 1);
        param.put("orderByStr", " add_time desc ");
        List<FeeCompanyEntity> firstFeeCompanyList = findEntitys(param);
        return firstFeeCompanyList.size() == 0 ? null : firstFeeCompanyList.get(0);
    }

    @Override
    public Integer getOrderType(Float payFee, Integer nowUserNum, Long nowEndTime, String corpid, boolean isDingdingCallBack) {
        if(Objects.equals(payFee, 0f)){
            return OrderTypeEnum.NEW_USER.getCode();
        }

        //第一条历史记录
        FeeCompanyEntity firstFeeCompany = getFirstFeeCompany(corpid);
        //没有历史记录，新用户开通
        if(firstFeeCompany == null){
            return OrderTypeEnum.NEW_USER.getCode();
        }
        Integer firstAddTime = firstFeeCompany.getAddTime();
        //当前时间-第一条付费记录的add_time小于等于30天，即30天内升级
        if(DateUtil.getInt() - firstAddTime <= 30*86400){
            return OrderTypeEnum.THIRTY_DAYS_WITHIN.getCode();
        }

        Long firstEndTime = firstFeeCompany.getEndTime();
        //已经超出30天了，当前截止时间小于等于第一条付费记录的截止时间，即30天外升级
        if(nowEndTime <= firstEndTime){
            return OrderTypeEnum.THIRTY_DAYS_OUTSIDE.getCode();
        }

        //最新的历史记录(firstFeeCompany!=null   lastFeeCompany不会为null)
        FeeCompanyEntity lastFeeCompany = getLastFeeCompany(corpid);
        Long lastEndTime = lastFeeCompany.getEndTime();
        //amdin使用自己系统的人数判断
        Integer lastUserNum = lastFeeCompany.getUserNum();
        //如果是钉钉回调，则使用钉钉的人数判断
        if(isDingdingCallBack){
            lastUserNum = lastFeeCompany.getUserNumDingding();
        }

        //当前截止时间大于最后一条付费记录的截止时间，即为续费，用户计算续费率
        if(nowEndTime > lastEndTime){
            return OrderTypeEnum.RENEWAL.getCode();
        }

        //当前使用人数大于最后一条的使用人数，即为续费升级
        if(  nowUserNum > lastUserNum){
            return OrderTypeEnum.RENEWAL_UPGRADE.getCode();
        }
        return null;
    }

    @Override
    public FeeCompanyEntity getNowFeeCompany(String corpid) {
        // 获取当前有效的套餐
        List<FeeCompanyEntity> feeCompanyEntityList = getEffectiveFeeCompanysByCorpid(corpid);
        FeeCompanyEntity feeCompanyEntity = null;

        //在有效时间内没有数据 获取最近过期的记录
        if (feeCompanyEntityList.isEmpty()) {
            return getEndTimeMaxFeeCompany(corpid);
        }

        removeFeeCompany(feeCompanyEntityList);
        List<FeeCompanyEntity> ultimateFeeCompanys = new ArrayList<>();

        feeCompanyEntityList.forEach(feeCompany->{
            if (Objects.equals(feeCompany.getFeeType(),PackageTypeEnum.ULTIMATE.getType())) {
                ultimateFeeCompanys.add(feeCompany);
            }
        });

        if (!ultimateFeeCompanys.isEmpty()) {
            feeCompanyEntity = getUserMoreFeeCompany(ultimateFeeCompanys);
        } else {
            feeCompanyEntity = getUserMoreFeeCompany(feeCompanyEntityList);
        }

        return feeCompanyEntity;
    }

    @Override
    public FeeCompanyEntity getCSMFeeCompany(String corpid) {
        //获取当前有效期未结束的CSM套餐
        FeeCompanyEntity feeCompany = getCSMFeeCompany(corpid, DateTimeUtil.getInt());
        //没有有效期未结束的CSM套餐，获取包含已过期的CSM套餐
        if (Objects.isNull(feeCompany)) {
            feeCompany = getCSMFeeCompany(corpid, null);
        }
        return feeCompany;
    }

    /**
     * 获取有效套餐（CSM）
     * @param corpid
     * @param startEndTime 截止时间 >= startEndTime
     * @return
     */
    FeeCompanyEntity getCSMFeeCompany(String corpid, Long startEndTime) {
        Map<String, Object> param = new HashMap<>();
        param.put("corpid", corpid);
        param.put("isActive", 1);
        param.put("isPay", 1);
        param.put("feeTypeIn", Arrays.asList(PackageTypeEnum.STANDARD.getType(),
                PackageTypeEnum.ADVANCED.getType(),
                PackageTypeEnum.ULTIMATE.getType()));
        if (Objects.nonNull(startEndTime)) {
            param.put("startEndTime", startEndTime);
        }
        param.put("del", 0);
        param.put("orderByStr", "end_time DESC,user_num DESC,fee_type DESC");
        List<FeeCompanyEntity> feeCompanys = findEntitys(param);
        return feeCompanys.isEmpty() ? null : feeCompanys.get(0);
    }

    /**
     * 获取截止时间最大的套餐
     * @param corpid
     * @return
     */
    FeeCompanyEntity getEndTimeMaxFeeCompany(String corpid) {
        return getEndTimeMaxFeeCompany(corpid, null);
    }

    /**
     * 获取截止时间最大的套餐
     * @param corpid
     * @param isPay
     * @return
     */
    FeeCompanyEntity getEndTimeMaxFeeCompany(String corpid, Integer isPay) {
        FeeCompanyEntity feeCompanyEntity = null;
        Map<String, Object> param = new HashMap<>();
        param.put("corpid", corpid);
        param.put("isActive", 1);
        param.put("isPay", isPay);
        param.put("feeTypeIn", Arrays.asList(PackageTypeEnum.STANDARD.getType(),
                PackageTypeEnum.ADVANCED.getType(),
                PackageTypeEnum.ULTIMATE.getType()));
        param.put("del", 0);
        param.put("orderByStr", "end_time DESC");
        List<FeeCompanyEntity> feeCompanys = findEntitys(param);
        if (!feeCompanys.isEmpty()) {
            feeCompanyEntity = feeCompanys.get(0);
        }
        return feeCompanyEntity;
    }

    @Override
    public List<FeeCompanyEntity> getByType(String corpid, int feeType) {
        return feeCompanyDao.getByType(corpid, feeType);
    }

    @Override
    public List<FeeCompanyEntity> getListByCorpid(String corpid, String feeNameLike) {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("feeNameLike", feeNameLike);
        param.put("del", DelEnum.NORMAL.getDel());
        return feeCompanyDao.findEntitys(param);
    }

    @Override
    public void setFeeCompanyInfo4Company(CompanyEntity company) throws XbbException {

        if (Objects.isNull(company)) {
            return ;
        }

        String corpid = company.getCorpid();
        List<FeeCompanyEntity> feeCompanyEntityList = getEffectiveFeeCompanysByCorpid(corpid);

        Long startTime = null;
        Long endTime = null;
        Integer addTime = null;
        String feeName = "";
        Integer feeType = null;
        Integer userNum = null;
        Integer orderType = null;
        Integer isFree = 1;
        String authChannel = "";
        String mainCorpid = "";
        for (FeeCompanyEntity feeCompany : feeCompanyEntityList) {
            //添加时间
            if (addTime == null ||
                    (Objects.nonNull(feeCompany.getAddTime()) && feeCompany.getAddTime() > addTime)) {
                addTime = feeCompany.getAddTime();
                authChannel = feeCompany.getAuthChannel();
            }

            //开始时间
            if (Objects.isNull(startTime) ||
                    (Objects.nonNull(feeCompany.getStartTime()) && feeCompany.getStartTime() < startTime)) {
                startTime = feeCompany.getStartTime();
            }

            //结束时间
            if (Objects.isNull(endTime) ||
                    (Objects.nonNull(feeCompany.getEndTime()) && feeCompany.getEndTime() > endTime)) {
                endTime = feeCompany.getEndTime();
            }

            //套餐类型及套餐名
            if (Objects.isNull(feeType) ||
                    (Objects.nonNull(feeCompany.getFeeType()) && feeCompany.getFeeType() > feeType)) {
                feeType = feeCompany.getFeeType();
                feeName = feeCompany.getFeeName();
            }

            //套餐人数
            if (Objects.isNull(userNum) ||
                    (Objects.nonNull(feeCompany.getUserNum()) && feeCompany.getUserNum() > userNum)) {
                userNum = feeCompany.getUserNum();
            }

            //订单类型
            if (Objects.isNull(orderType) ||
                    (Objects.nonNull(feeCompany.getOrderType()) && feeCompany.getOrderType() > orderType)) {
                orderType = feeCompany.getOrderType();
            }

            if (Objects.equals(feeCompany.getIsPay(), BasicConstant.ONE)) {
                isFree = 0;
            }
            if ( Objects.nonNull(feeCompany.getMainCorpid()) && StringUtil.isEmpty(mainCorpid) ) {
                mainCorpid = feeCompany.getMainCorpid();
            }
        }

        Integer vipNum = feeCompanyModel.getBuyNum(corpid);
        company.setIsFree(isFree);
        authChannel = StringUtil.isEmpty(authChannel) ? company.getAuthChannel() : authChannel;

        // 判断是否需要更新
        if(checkCompanyFeeInfo(startTime, endTime, feeName, feeType, userNum, orderType,
                mainCorpid, vipNum, authChannel, company)) {
            return;
        }

        company.setFeeStartTime(startTime);
        company.setFeeEndTime(endTime);
        company.setFeeName(feeName);
        company.setFeeType(feeType);
        company.setFeeUserNum(userNum);
        company.setOrderType(orderType);
        company.setMainCorpid(mainCorpid);
        company.setVipNum(vipNum);
        company.setUpdateTime(DateTimeUtil.getInt());

        company.setAuthChannel(authChannel);
        companyModel.update(company);
    }

    /**
     * 判断是否需要更新数据库中公司表记录，依据为本方法参数是否与数据库中对应值不同
     * @return 返回 true 表示与数据库相同，不用更新；返回 false 则需要更新
     */
    private boolean checkCompanyFeeInfo(Long startTime, Long endTime, String feeName, Integer feeType,
                                        Integer userNum, Integer orderType, String mainCorpid, Integer vipNum,
                                        String authChannel, CompanyEntity company) {

        if (Objects.equals(startTime, company.getFeeStartTime()) && Objects.equals(endTime, company.getFeeEndTime())
                && Objects.equals(feeName, company.getFeeName()) && Objects.equals(feeType, company.getFeeType())
                && Objects.equals(userNum, company.getFeeUserNum()) && Objects.equals(orderType, company.getOrderType())
                && Objects.equals(mainCorpid, company.getMainCorpid()) && Objects.equals(vipNum, company.getVipNum())
                //判断两个authChannel是否相同，需要处理null的情况
                && ((authChannel == null && company.getAuthChannel() == null) || Objects.equals(authChannel, company.getAuthChannel()))) {
            return true;
        }
        return false;
    }

    /**
     * 当feeCompanyEntityList中有付费套餐，移除其中的免费套餐
     * @param feeCompanyEntityList
     */
    private void removeFeeCompany(List<FeeCompanyEntity> feeCompanyEntityList) {

        boolean hasPay = false;
        for (FeeCompanyEntity feeCompany : feeCompanyEntityList) {
            Integer isPay = feeCompany.getIsPay();
            Integer isActive = feeCompany.getIsActive();
            if (Objects.equals(isPay, 1) && Objects.equals(isActive, 1)) {
                hasPay = true;
                break;
            }
        }

        //没有已付费套餐
        if (!hasPay) {
            return ;
        }

        Iterator<FeeCompanyEntity> iterator = feeCompanyEntityList.iterator();

        while (iterator.hasNext()) {
            FeeCompanyEntity feeCompany = iterator.next();
            Integer isPay = feeCompany.getIsPay();
            Integer isActive = feeCompany.getIsActive();
            hasPay = Objects.equals(isPay, 1) && Objects.equals(isActive, 1);

            //移除免费套餐
            if (!hasPay) {
                iterator.remove();
            }
        }
    }

    /**
     * 获取人数较多的套餐
     * @param feeCompanys
     * @return
     * 创建时间 2019/6/27 8:07 PM
     * 修改时间 2019/6/27 8:07 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private FeeCompanyEntity getUserMoreFeeCompany(List<FeeCompanyEntity> feeCompanys) {
        if (feeCompanys == null || feeCompanys.isEmpty()) {
            return null;
        }
        FeeCompanyEntity feeCompanyEntity = null;
        for (FeeCompanyEntity feeCompany : feeCompanys) {
            if (feeCompanyEntity == null) {
                feeCompanyEntity = feeCompany;
                continue;
            }
            //人数相同时，截止时间晚的为准
            if (Objects.equals(feeCompany.getUserNum(), feeCompanyEntity.getUserNum())) {
                if (feeCompany.getEndTime() > feeCompanyEntity.getEndTime()) {
                    feeCompanyEntity = feeCompany;
                    continue;
                }
            }
            if (feeCompany.getUserNum() > feeCompanyEntity.getUserNum()) {
                feeCompanyEntity = feeCompany;
            }
        }
        return feeCompanyEntity;
    }

    /**
     * 获取当前时间有效的套餐，按添加时间倒序
     * @param corpid
     * @return
     * 创建时间 2020/5/25 9:29 AM
     * 修改时间 2020/5/25 9:29 AM
     * @author chy
     */
    private List<FeeCompanyEntity> getEffectiveFeeCompanysByCorpid(String corpid) {
        return getEffectiveFeeCompanysByCorpid(corpid, null);
    }

    /**
     * 获取当前时间有效的套餐，按添加时间倒序
     * @param corpid
     * @param isPay
     * @return
     * 创建时间 2020/5/25 9:29 AM
     * 修改时间 2020/5/25 9:29 AM
     * @author chy
     */
    private List<FeeCompanyEntity> getEffectiveFeeCompanysByCorpid(String corpid, Integer isPay) {
        Map<String, Object> param = new HashMap<>();
        param.put("corpid", corpid);
        param.put("isActive", 1);
        param.put("isPay", isPay);
        param.put("feeTypeIn", Arrays.asList(PackageTypeEnum.FREE.getType(),
                PackageTypeEnum.STANDARD.getType(),
                PackageTypeEnum.ADVANCED.getType(),
                PackageTypeEnum.ULTIMATE.getType()));
        param.put("timeBetween", DateTimeUtil.getInt());
        param.put("del", 0);
        param.put("orderByStr", "end_time desc");
        return findEntitys(param);
    }
}
